﻿#include <QMetaObject>
#include "QBlock.h"
#include "QFlowChartStyle.h"
#include "QFlowChart.h"
#include "ProcessBlock.h"
#include "IFBlock.h"
#include "InputBlock.h"
#include "AlgorithmBlock.h"
#include "OutputBlock.h"
#include "AssignBlock.h"
#include "PreloopBlock.h"
#include "PostloopBlock.h"
#include "ForBlock.h"
#include "ParallelBlock.h"
#include "SubFlowBlock.h"

#include "AbstractEntity.h"

#include <QRegExp>

using namespace CVV::Interface;
using namespace CVV::Entity;

namespace CVV
{
namespace FlowChart
{

QBlock::QBlock(QWidget *parent)
    : QWidget(parent)
    , m_dX(0)
    , m_dY(0)
    , m_dWidth(0)
    , m_dHeight(0)
    , m_dExpandW(0)
    , m_dExpandH(0)
    , m_dTopMargin(0)
    , m_dBottomMargin(0)
    , m_dLeftMargin(0)
    , m_dRightMargin(0)
{
    setContextMenuPolicy(Qt::ActionsContextMenu);

    m_hashAttributes.clear();
    m_lstChildItems.clear();
    m_pluginInfoList.clear();
}

QBlock::QBlock(QMenu *blockMenu, const QString &aType, QWidget *parent)
    : QWidget(parent)
    , m_dX(0)
    , m_dY(0)
    , m_dWidth(0)
    , m_dHeight(0)
    , m_dExpandW(0)
    , m_dExpandH(0)
    , m_dTopMargin(0)
    , m_dBottomMargin(0)
    , m_dLeftMargin(0)
    , m_dRightMargin(0)
    , m_pBlockMenu(blockMenu)
{
    m_hashAttributes.clear();
    m_lstChildItems.clear();
    m_pluginInfoList.clear();

    setType(aType);
}

QBlock::~QBlock()
{
    if(m_pParentBlock)
    {
        m_pParentBlock->remove(this);
    }
    clear();
}


QBlock* QBlock::root()
{
    if (!m_pParentBlock)
    {
        return this;
    }

    return m_pParentBlock->root();
}

void QBlock::setIsSubProcess()
{
    m_bSubProcess = true;
}

bool QBlock::isBockType(QFlowEnum::BlockType blocktype) const
{
    return type() == QFlowEnum::getEnumNameByKey<QFlowEnum::BlockType>(blocktype).toLower();
}

QString QBlock::type(int flag) const
{
    Q_UNUSED(flag)
    return  m_hashAttributes.value("type");
}

void QBlock::setType(const QString &newType)
{
    m_hashAttributes["type"] = newType;
}

int QBlock::index()
{
    if(!m_pParentBlock)
    {
        return -1;
    }

    return m_pParentBlock->m_lstChildItems.indexOf(this);
}


void QBlock::insert(int newIndex, QBlock *aBlock)
{
    if (aBlock->m_pParentBlock != nullptr)
    {
        aBlock->m_pParentBlock->remove(aBlock);
    }
    if (newIndex < 0 || newIndex >= m_lstChildItems.size())
    {
        m_lstChildItems.append(aBlock);
    }
    else
    {
        m_lstChildItems.insert(newIndex, aBlock);
    }

    aBlock->m_pParentBlock = this;
    aBlock->setFlowChart(flowChart());
}

void QBlock::remove(QBlock *aBlock)
{
    m_lstChildItems.removeAll(aBlock);
    aBlock->m_pParentBlock = nullptr;
    aBlock->setFlowChart(nullptr);
}

void QBlock::append(QBlock *aBlock)
{
    insert(-1, aBlock);
}

void QBlock::deleteObject(int aIndex)
{
    QBlock *tmp = item(aIndex);
    if(tmp)
    {
        delete tmp;
        tmp = nullptr;
    }
}

QBlock *QBlock::item(int aIndex) const
{
    if (m_lstChildItems.isEmpty() || aIndex < 0 || aIndex >= m_lstChildItems.size())
    {
        return nullptr;
    }

    return m_lstChildItems.at(aIndex);
}

void QBlock::setItem(int aIndex, QBlock *aBlock)
{
    if(m_lstChildItems.size() > aIndex && aIndex >= 0)
    {
        if (aBlock->m_pParentBlock)
        {
            aBlock->m_pParentBlock->remove(aBlock);
        }
        QBlock *old = item(aIndex);
        old->m_pParentBlock = nullptr;
        m_lstChildItems.replace(aIndex, aBlock);
    }
}

QFlowChart *QBlock::flowChart() const
{
    return m_pFlowChart;
}

void QBlock::setFlowChart(QFlowChart * aFlowChart)
{
    m_pFlowChart = aFlowChart;
}


void QBlock::clear()
{
    for (int i = m_lstChildItems.size() - 1; i >= 0; --i)
    {
        QBlock* pObj = m_lstChildItems.at(i);
        delete pObj;
        pObj = nullptr;
    }

    QString currentType = type();
    m_hashAttributes.clear();
    setType(currentType);
    m_lstChildItems.clear();
}

//调整尺寸,更具展开属性,和是否可见
void QBlock::adjustSize(const double aZoom)
{
    double clientWidth = 0, clientHeight = 0;
    if (m_bIsBranch)
    {
        for (int i = 0; i < m_lstChildItems.size(); ++i)
        {
            item(i)->adjustSize(aZoom);
            if (clientWidth < item(i)->m_dWidth)
            {
                clientWidth = item(i)->m_dWidth;
            }
            clientHeight += item(i)->m_dHeight;
        }
        double minWidth = 180 * aZoom;
        double minHeight = 16 * aZoom;
        if (clientHeight < minHeight)
        {
            clientHeight = minHeight;
        }

        if (clientWidth < minWidth)
        {
            clientWidth = minWidth;
        }
        if(m_bIsExpand && m_bVisible)
        {
            m_dHeight = clientHeight;
            m_dWidth = clientWidth;
            m_dExpandH = clientHeight;
            m_dExpandW = clientWidth;
        }
    }
    else
    {
        for (int i = 0; i < m_lstChildItems.size(); ++i)
        {
            item(i)->adjustSize(aZoom);
            if (clientHeight < item(i)->m_dHeight)
            {
                clientHeight = item(i)->m_dHeight;
            }

            clientWidth += item(i)->m_dWidth;
        }

        m_dTopMargin = 60 * aZoom;
        m_dBottomMargin = 60 * aZoom;
        m_dLeftMargin = 10 * aZoom;
        m_dRightMargin = 10 * aZoom;

        if (isBockType(QFlowEnum::BlockType::Algorithm))
        {
            m_dTopMargin = 40 * aZoom;
            m_dBottomMargin = 50 * aZoom;
        }
        else if (isBockType(QFlowEnum::BlockType::Process)
                 || isBockType(QFlowEnum::BlockType::Assign)
                 || isBockType(QFlowEnum::BlockType::SubFlow))
        {
            m_dTopMargin = 16 * aZoom;
            m_dBottomMargin = 10 * aZoom;
            m_dLeftMargin = 20 * aZoom;
            m_dRightMargin = 20 * aZoom;
            clientWidth = 120 * aZoom;
            clientHeight = 60 * aZoom;
        }
        else if (isBockType(QFlowEnum::BlockType::IO))
        {
            m_dTopMargin = 16 * aZoom;
            m_dBottomMargin = 10 * aZoom;
            m_dLeftMargin = 20 * aZoom;
            m_dRightMargin = 20 * aZoom;
            clientWidth = 120 * aZoom;
            clientHeight = 60 * aZoom;
        }
        else if (isBockType(QFlowEnum::BlockType::OU))
        {
            m_dTopMargin = 16 * aZoom;
            m_dBottomMargin = 10 * aZoom;
            m_dLeftMargin = 20 * aZoom;
            m_dRightMargin = 20 * aZoom;
            clientWidth = 120 * aZoom;
            clientHeight = 60 * aZoom;
        }
        else if (isBockType(QFlowEnum::BlockType::IF)
                 || isBockType(QFlowEnum::BlockType::Parallel))
        {
            m_dTopMargin = 92 * aZoom;
            m_dBottomMargin = 16 * aZoom;
        }
        else if (isBockType(QFlowEnum::BlockType::Pre))
        {
            m_dTopMargin = 108 * aZoom;
            m_dBottomMargin = 32 * aZoom;
        }
        else if (isBockType(QFlowEnum::BlockType::Post))
        {
            m_dTopMargin = 16 * aZoom;
            m_dBottomMargin = 96 * aZoom;
        }
        else if (isBockType(QFlowEnum::BlockType::For))
        {
            m_dTopMargin = 108 * aZoom;
            m_dBottomMargin = 32 * aZoom;
        }

        if(m_bIsExpand && m_bVisible)
        {
            m_dWidth = (m_dLeftMargin + clientWidth + m_dRightMargin);
            m_dHeight = (m_dTopMargin + clientHeight + m_dBottomMargin);
            m_dExpandH = m_dHeight;
            m_dExpandW = m_dWidth;
        }
        qDebug()<< __FUNCTION__ << "x:" << m_dX << "y:" << m_dY << "w:" << m_dWidth <<"h:" << m_dHeight;
    }
}

void QBlock::adjustPosition(const double ox, const double oy)
{
    m_dX = ox;
    m_dY = oy;
    if (m_bIsBranch)
    {
        double cy = m_dY;
        for (int i = 0; i < m_lstChildItems.size(); ++i)
        {
            item(i)->adjustPosition(ox + (m_dWidth - item(i)->m_dWidth) / 2, cy);
            cy += item(i)->m_dHeight;
        }
    }
    else
    {
        double cx = m_dX + m_dLeftMargin;
        for (int i = 0; i < m_lstChildItems.size(); ++i)
        {
            item(i)->adjustPosition(cx, m_dY + m_dTopMargin);
            cx += item(i)->m_dWidth;
        }
    }
}


void QBlock::paint(QPainter *canvas, bool fontSizeInPoints)
{
    if (flowChart())
    {
        QFlowChartStyle st = flowChart()->chartStyle();
        double hcenter = m_dX + m_dWidth / 2;

        QFont font("Tahoma");
        font.setWeight(0);
        if (fontSizeInPoints)
        {
            font.setPointSizeF(10 * zoom());
        }
        else
        {
            font.setPixelSize(static_cast<int>(13 * zoom()));
        }
        //判断是否可见
        if(m_bVisible)
        {
            font = QFont(font, canvas->device());
            canvas->setFont(font);
            canvas->setBrush(QBrush());
            QPen oldPen = canvas->pen();

            if(flowChart()->status() == QFlowChart::Selectable &&
                    (isActive() || flowChart()->getCtrlEnable() ||
                     flowChart()->getFindTargetBlocksCount() > 0))
            {
                if(m_bCurFindActive && m_bFindActive)
                {
                    paintBlockMargin(canvas, QColor(0xFF, 0xEF, 0x0B), m_bSelectAll);
                    QPen pen = canvas->pen();
                    pen.setColor(QColor(0x12,0x96,0xdb));
                }
                else if(!m_bCurFindActive && m_bFindActive)
                {
                    paintBlockMargin(canvas, QColor(0x49, 0xDF, 0xE7), m_bSelectAll);
                    QPen pen = canvas->pen();
                    pen.setColor(QColor(0x12,0x96,0xdb));
                }
                else if(!m_bCurFindActive && m_bSelectAll)
                {
                    paintBlockMargin(canvas);
                }
            }
            else
            {
                ////            canvas->fillRect(QRectF(x, y, width, height), canvas->brush());
            }

            if(flowChart()->status() == QFlowChart::Selectable && flowChart()->getFlowChartMenuShowState())
            {
                if(m_bCurFindActive && m_bFindActive)
                {
                    paintBlockMargin(canvas, QColor(0xFF, 0xEF, 0x0B), m_bSelectAll);
                    QPen pen = canvas->pen();
                    pen.setColor(QColor(0x12,0x96,0xdb));
                }
                else if(!m_bCurFindActive && m_bFindActive)
                {
                    paintBlockMargin(canvas, QColor(0x49, 0xDF, 0xE7), m_bSelectAll);
                    QPen pen = canvas->pen();
                    pen.setColor(QColor(0x12,0x96,0xdb));
                }
                else if(!m_bCurFindActive && m_bSelectAll)
                {
                    paintBlockMargin(canvas);
                }
            }
            canvas->setPen(oldPen);
            QPen pen = canvas->pen();
            pen.setColor(Qt::black);
            pen.setCapStyle(Qt::FlatCap);
            pen.setJoinStyle(Qt::MiterJoin);
            canvas->setPen(pen);
            //填充背景白色颜色给去除
            QStringList unReferencedLst = flowChart()->getUnReferencedIdLst();
            QStringList curReferencedLst = flowChart()->getReferencedIdLst();
            if (m_bIsBranch)
            {
                /* 分支线绘制 */
                QLineF line(hcenter, m_dY - 0.5, hcenter, m_dY + m_dHeight + 0.5);
                //分支有子分支线则不需要绘制主线
                if(0 == m_lstChildItems.size())
                {
                    QColor col(0x12, 0x96, 0xdb);
                    QPen oldP =  canvas->pen();
                    QPen pe(col);
                    pe.setWidthF(2);
                    canvas->setPen(pe);
                    canvas->drawLine(line);
                    canvas->setPen(oldP);
                }
            }
            else
            {
                canvas->setBrush(QBrush(st.normalBackground()));

                auto updateReferenceState = [this](AbstractBlock &block, QStringList unReferencedLst, QStringList curReferencedLst ){
                    int iState = -1;

                    if((!unReferencedLst.contains(m_strId)) && (!curReferencedLst.contains(m_strId)))
                    {
                        iState = -1;
                    }
                    else if(unReferencedLst.contains(m_strId) && (!curReferencedLst.contains(m_strId)))
                    {
                        iState = 0;
                    }
                    else if((!unReferencedLst.contains(m_strId)) && curReferencedLst.contains(m_strId))
                    {
                        iState = 1;
                    }
                    else if(unReferencedLst.contains(m_strId) && curReferencedLst.contains(m_strId))
                    {
                        iState = 2;
                    }
                    block.setReferenceStatus(iState);
                };
                int icellId = m_strId.toInt();
                int iState = flowChart()->getCellResultState(icellId);
                if (isBockType(QFlowEnum::BlockType::Algorithm))
                {
                    QRect rect_position(static_cast<int>(m_dX), static_cast<int>(m_dY), static_cast<int>(m_dWidth), static_cast<int>(m_dHeight));
                    QString id = m_hashAttributes.value("id");
                    QString blockName = QString("%1.AlgorithmBlock").arg(id);
                    AlgorithmBlock algorithmBlock(blockName, rect_position, zoom());
                    algorithmBlock.setBranchItem(m_lstChildItems);
                    algorithmBlock.paint(canvas);
                }
                else if(isBockType(QFlowEnum::BlockType::Process))
                {
                    QRect rect_position(static_cast<int>(m_dX), static_cast<int>(m_dY), static_cast<int>(m_dWidth), static_cast<int>(m_dHeight));
                    QString id = m_hashAttributes.value("id");
                    QString title = m_hashAttributes.value("title");
                    QString blockName = QString("%1.%2").arg(id).arg(title);
                    QString state = m_hashAttributes.value("state");
                    if(1 == iState)
                    {
                        state = "RunSuccessfully";
                    }
                    else if(-1 == iState)
                    {
                        state = "RunError";
                    }
                    ProcessBlock processBlock(blockName, rect_position, zoom(), state);
                    if(unReferencedLst.size() > 0 || curReferencedLst.size() > 0)
                    {
                        updateReferenceState(processBlock, unReferencedLst, curReferencedLst);
                    }
                    processBlock.paint(canvas);
                }
                else if(isBockType(QFlowEnum::BlockType::Assign))
                {
                    QRect rect_position(static_cast<int>(m_dX), static_cast<int>(m_dY), static_cast<int>(m_dWidth), static_cast<int>(m_dHeight));
                    QString id = m_hashAttributes.value("id");
                    QString title = m_hashAttributes.value("dest") + ":" + m_hashAttributes.value("src");
                    QString blockName = QString("%1.%2").arg(id).arg(title);
                    AssignBlock assBlock(blockName, rect_position, zoom());
                    assBlock.paint(canvas);
                }
                else if(isBockType(QFlowEnum::BlockType::IO))
                {
                    QRect rect_position(static_cast<int>(m_dX), static_cast<int>(m_dY), static_cast<int>(m_dWidth), static_cast<int>(m_dHeight));
                    QString id = m_hashAttributes.value("id");
                    QString title = m_hashAttributes.value("title");
                    QString blockName = QString("%1.%2").arg(id).arg(title);
                    QString state = m_hashAttributes.value("state");
                    if(1 == iState)
                    {
                        state = "RunSuccessfully";
                    }
                    else if(-1 == iState)
                    {
                        state = "RunError";
                    }
                    InputBlock inPutBlock(blockName, rect_position, zoom(), state);
                    if(unReferencedLst.size() > 0  || curReferencedLst.size() > 0)
                    {
                        updateReferenceState(inPutBlock, unReferencedLst, curReferencedLst);
                    }
                    inPutBlock.paint(canvas);

                }
                else if(isBockType(QFlowEnum::BlockType::OU))
                {
                    QRect rect_position(static_cast<int>(m_dX), static_cast<int>(m_dY), static_cast<int>(m_dWidth), static_cast<int>(m_dHeight));

                    QString id = m_hashAttributes.value("id");
                    QString title = m_hashAttributes.value("title");
                    QString blockName = QString("%1.%2").arg(id).arg(title);
                    QString state = m_hashAttributes.value("state");
                    if(1 == iState)
                    {
                        state = "RunSuccessfully";
                    }
                    else if(-1 == iState)
                    {
                        state = "RunError";
                    }
                    OutputBlock outPutBlock(blockName, rect_position, zoom(), state);
                    if(unReferencedLst.size() > 0  || curReferencedLst.size() > 0)
                    {
                        updateReferenceState(outPutBlock, unReferencedLst, curReferencedLst);
                    }
                    outPutBlock.paint(canvas);
                }
                else if(isBockType(QFlowEnum::BlockType::IF))
                {
                    QRect rect_position(static_cast<int>(m_dX), static_cast<int>(m_dY), static_cast<int>(m_dWidth), static_cast<int>(m_dHeight));
                    QString id = m_hashAttributes.value("id");
                    QString title = m_hashAttributes.value("title");
                    QString blockName = QString("%1.%2").arg(id).arg(title);
                    IFBlock ifBlock(blockName, rect_position, zoom(), m_bIsExpand);
                    ifBlock.setBranchItem(m_lstChildItems);
                    ifBlock.paint(canvas);
                }
                else if(isBockType(QFlowEnum::BlockType::Pre))
                {
                    QRect rect_position(static_cast<int>(m_dX), static_cast<int>(m_dY), static_cast<int>(m_dWidth), static_cast<int>(m_dHeight));
                    QString id = m_hashAttributes.value("id");
                    QString title = m_hashAttributes.value("title");
                    QString blockName = QString("%1.%2").arg(id).arg(title);
                    PreloopBlock preBlock(blockName, rect_position, zoom(), m_bIsExpand);
                    preBlock.setBranchItem(m_lstChildItems);
                    preBlock.paint(canvas);

                }
                else if(isBockType(QFlowEnum::BlockType::Post))
                {
                    QRect rect_position(static_cast<int>(m_dX), static_cast<int>(m_dY), static_cast<int>(m_dWidth), static_cast<int>(m_dHeight));
    //                QString blockName = m_hashAttributes.value("cond");
                    QString id = m_hashAttributes.value("id");
                    QString title = m_hashAttributes.value("title");
                    QString blockName = QString("%1.%2").arg(id).arg(title);
                    PostloopBlock postBlock(blockName, rect_position, zoom(), m_bIsExpand);
                    postBlock.setBranchItem(m_lstChildItems);
                    postBlock.paint(canvas);

                }
                else if(isBockType(QFlowEnum::BlockType::For))
                {
                    QRect rect_position(static_cast<int>(m_dX), static_cast<int>(m_dY), static_cast<int>(m_dWidth), static_cast<int>(m_dHeight));
    //                QString blockName = m_hashAttributes.value("vars") + ":" + m_hashAttributes.value("from") + ":" + m_hashAttributes.value("to");
                    QString id = m_hashAttributes.value("id");
                    QString title = m_hashAttributes.value("title");
                    QString blockName = QString("%1.%2").arg(id).arg(title);
                    ForBlock forBlock(blockName, rect_position, zoom(), m_bIsExpand);
                    forBlock.setBranchItem(m_lstChildItems);
                    forBlock.paint(canvas);
                }
                else if(isBockType(QFlowEnum::BlockType::Parallel))
                {
                    QRect rect_position(static_cast<int>(m_dX), static_cast<int>(m_dY), static_cast<int>(m_dWidth), static_cast<int>(m_dHeight));
                    QString id = m_hashAttributes.value("id");
                    QString title = tr("Parallel Branch");
                    QString blockName = QString("%1.%2").arg(id).arg(title);
                    ParallelBlock paraBlock(blockName, rect_position, zoom(), m_bIsExpand);
                    paraBlock.setBranchItem(m_lstChildItems);
                    paraBlock.paint(canvas);
                }
                else if (isBockType(QFlowEnum::BlockType::SubFlow))
                {
                    QRect rect_position(static_cast<int>(m_dX), static_cast<int>(m_dY), static_cast<int>(m_dWidth), static_cast<int>(m_dHeight));
                    QString id = m_hashAttributes.value("id");
                    QString title = m_hashAttributes.value("title");
                    QString blockName = QString("%1.%2").arg(id).arg(title);
                    QString state = m_hashAttributes.value("state");
                    if(1 == iState)
                    {
                        state = "RunSuccessfully";
                    }
                    else if(-1 == iState)
                    {
                        state = "RunError";
                    }
                    SubFlowBlock subFlowBlock(blockName, rect_position, zoom(), state);
                    if(unReferencedLst.size() > 0  || curReferencedLst.size() > 0)
                    {
                        updateReferenceState(subFlowBlock, unReferencedLst, curReferencedLst);
                    }
                    subFlowBlock.paint(canvas);
                }

            }
            //canvas->drawText(x+8, y+12, type());
        }

        for(int i = 0; i < m_lstChildItems.size(); ++i)
        {
            item(i)->paint(canvas, fontSizeInPoints);
        }
    }
}

void QBlock::paintBlockMargin(QPainter *canvas, QColor col, bool isSelected)
{
    QPen pen = canvas->pen();
    pen.setColor(col);
    pen.setWidth(2);
    if(isSelected)
    {
        pen.setWidth(4);
    }
    pen.setStyle(Qt::DotLine);//虚线框
    canvas->setPen(pen);
    if(root() == this)
    {
        canvas->drawRect(QRectF(m_dX, m_dY, m_dWidth, m_dHeight));
    }
    else {
        canvas->drawRect(QRectF(m_dX+2, m_dY+2, m_dWidth-4, m_dHeight-4));
    }
}

double QBlock::zoom() const
{
    if (flowChart())
    {
        return flowChart()->zoom();
    }

    return 1;
}

QBlock * QBlock::blockAt(int px, int py)
{
    QRectF rect(m_dX, m_dY, m_dWidth, m_dHeight);
    if (!rect.contains(px, py))
    {
        return nullptr;
    }

    for (int i = 0; i < m_lstChildItems.size(); ++i)
    {
        if(!item(i)->getBlockVisible())
        {
            continue;
        }
        QBlock *tmp = item(i)->blockAt(px, py);
        if (tmp)
        {
            return tmp;
        }
    }

    return this;
}


void QBlock::drawCaption(QPainter *canvas, const QRectF & rect, const double zoomFactor, const QString & text)
{
    QFont font("Sans Serif");
    font.setPixelSize(static_cast<int>(13 * zoomFactor));
    font = QFont(font, canvas->device());
    QFontMetricsF fontMetrics(font);
    QRectF textRect = fontMetrics.boundingRect(text);
    double tx = rect.x() + rect.width() / 2 - textRect.width() / 2;
    double ty = rect.y() + rect.height() / 2 + fontMetrics.ascent() / 2;
    canvas->setFont(font);
    //canvas->drawRect(tx, ty - textRect.height(), textRect.width(), textRect.height());
    canvas->drawText(QPointF(tx, ty), text);

}


//获取所有的xml节点,保存为xml文件
QDomElement QBlock::xmlNode(QDomDocument & doc) const
{
    QDomElement self = doc.createElement(type());
    QList<QString> sl = m_hashAttributes.uniqueKeys();
    for (int i = 0; i < sl.size(); ++i)
    {
        if (sl.at(i) != "type"&&sl.at(i)!="state")
        {
            self.setAttribute(sl.at(i), m_hashAttributes.value(sl.at(i), QString()));
        }
    }

    if (m_hashAttributes.contains("isPlugin"))
    {
        if(m_hashAttributes.value("isPlugin", QString()).compare("true") == 0)
        {
            QDomElement pluginElement = doc.createElement("plugininfo");
            QDomElement cellElement = doc.createElement("cellparam");
            createCellParamNode(doc, cellElement);
            pluginElement.appendChild(cellElement);

            // 算法参数
            if (!m_lstAlgParam.isEmpty())
            {
                QDomElement algElement = doc.createElement("algorithmparam");
                createAlgorithmParamNode(doc, algElement);
                pluginElement.appendChild(algElement);
            }
            self.appendChild(pluginElement);
        }
    }
    for (int i = 0; i < m_lstChildItems.size(); ++i)
    {
        if(nullptr != item(i))
        {
            QDomElement child = item(i)->xmlNode(doc);
            self.appendChild(child);
        }
    }

    return self;
}

//打开流程xml文件，读取节点
void QBlock::setXmlNode(const QDomElement & node)
{
    /**清空**/
    clear();
    setType(node.nodeName());
    QDomNamedNodeMap attrs = node.attributes();
    for (int i = 0; i < attrs.size(); ++i)
    {
        QDomAttr da = attrs.item(i).toAttr();
        QString daname = da.name();
        if("type" != daname)
        {
            m_hashAttributes.insert(daname, da.value());
            if("describe" == daname)
            {
                m_descibe = da.value();
            }
            else if("scene" == daname)
            {
                m_scene = da.value();
            }
        }
    }
    m_bIsBranch = (type() == "branch");

    QDomNodeList children = node.childNodes();
    for(int i = 0; i < children.size(); ++i)
    {
        if (children.at(i).isElement())
        {
            QDomElement child = children.at(i).toElement();
            if(0 == child.nodeName().compare("plugininfo"))
            {
                continue;
            }

            QBlock *block = new QBlock();
            if(0 == child.nodeName().compare("subflow"))
            {
                block->setIsSubProcess();
            }
            m_child = child;
            block->setFlowChart(flowChart());
            QString strBlockExpand = child.attribute("blockExpand");
            bool bExpand = ((0 == strBlockExpand.compare("false")) ? false : true);
            block->setBlockExpandState(bExpand);

            QString strBlockVisble = child.attribute("blockVisible");
            bool bVisible = ((0 == strBlockVisble.compare("false")) ? false : true);
            block->setBlockVisible(bVisible);
            block->setXmlNode(child);
            if (!block->m_bIsBranch)
            {
                block->setId(child.attribute("id"));
                block->setPreId(child.attribute("preId"));
            }
            else
            {
                bool bEnable = true;
                if (child.hasAttribute("isEnable"))
                {
                    bEnable = (child.attribute("isEnable") == "true");
                }
                block->setBranchEnable(bEnable);
            }
            append(block);
        }
    }
}

QBlock* QBlock::insertXmlTree(int aIndex, const QDomElement &algorithm)
{
    QBlock *block = nullptr;
    if (m_bIsBranch)
    {
        QDomElement branch = algorithm.firstChildElement("branch");
        if(!branch.isNull())
        {
            QDomNodeList children = branch.childNodes();
            int ind = aIndex;
            for(int i = 0; i < children.size(); ++i)
            {
                if (children.at(i).isElement())
                {
                    QDomElement child = children.at(i).toElement();
                    int idx = 0;
                    if (aIndex >= 0)
                    {
                        idx = aIndex - 1;
                    }
                    else
                    {
                        idx = m_lstChildItems.size() - 1;
                    }

                    QBlock *pBlock = item(idx);
                    if (pBlock)
                    {
                        if (!pBlock->m_lstChildItems.isEmpty())
                        {
                            QString strPreId = findPreId(pBlock);
                            child.setAttribute("preId", strPreId);
                        }
                        else
                        {
                            child.setAttribute("preId", pBlock->id());
                        }
                    }
                    else if (m_pParentBlock)
                    {
                        if ("false" == m_pParentBlock->m_hashAttributes.value("isPlugin"))
                        {
                            child.setAttribute("preId", m_pParentBlock->preId());
                        }
                        else
                        {
                            child.setAttribute("preId", m_pParentBlock->id());
                        }
                    }

                    block = new QBlock(m_pBlockMenu);
                    block->setId(child.attribute("id"));
                    block->setPreId(child.attribute("preId"));
                    block->setFlowChart(flowChart());
                    block->setXmlNode(child);
                    insert(ind, block);
                    updateAfterInsertNodePreId(child.attribute("id"), ind + 1);
                    ind++;
                }
            }
        }
    }
    return block;
}

void QBlock::modify(int num, bool bAdd, const QList<int>& lstDeleteIndex)
{
    if(bAdd)
    {
        if (m_child.hasChildNodes())
        {
            qDebug() << __FUNCTION__ << "remove all child";
            QDomNodeList children = m_child.childNodes();
            int iCount = children.size();
            for(int i = iCount - 1; i >= 0; --i)
            {
                m_child.removeChild(children.at(i));
            }
        }
        for(int i = 0;i < num;i++)
        {
            QBlock *childBlock = new QBlock();
            childBlock->setFlowChart(flowChart());
            childBlock->m_child = m_child;
            childBlock->setXmlNode(m_child);
            append(childBlock);
        }
    }
    else
    {
        // 倒序
        QList<int> lstIndex = lstDeleteIndex;
        std::sort(lstIndex.begin(), lstIndex.end(), std::greater<int>());
        for (int i = 0; i < lstIndex.size(); ++i)
        {
            int index = lstIndex.at(i);
            if (index < m_lstChildItems.size())
            {
                QBlock* pBlock = m_lstChildItems.takeAt(index);
                if (pBlock)
                {
                    pBlock->m_pParentBlock = nullptr;
                    pBlock->setFlowChart(nullptr);
                    pBlock->deleteLater();
                    pBlock = nullptr;
                }
            }
        }
//        for(int i = 0;i < num;i++)
//        {
//            QBlock* lastBloc = m_lstChildItems.last();
//            lastBloc->m_pParentBlock = nullptr;
//            lastBloc->setFlowChart(nullptr);
//            m_lstChildItems.removeLast();
//        }
    }
}

void QBlock::updateParallelBranchStatus(const QList<int> &lstEnableIndex)
{
    for (int i = 0; i < m_lstChildItems.size(); ++i)
    {
        QBlock* pBlock = m_lstChildItems.at(i);
        if (lstEnableIndex.contains(i))
        {
            pBlock->setBranchEnable(true);
        }
        else
        {
            pBlock->setBranchEnable(false);
        }
    }
}

bool QBlock::isActive() const
{
    if(flowChart())
    {
        if (flowChart()->activeBlock() == this)
        {
            return true;
        }
        else if (m_pParentBlock)
        {
            return m_pParentBlock->isActive();
        }
        else
        {
            return false;
        }
    }

    return false;
}

void QBlock::setPluginInfo(const QList<CVV::Interface::FlowCellParam> &param)
{
    m_pluginInfoList = param;
}

QList<Interface::FlowCellParam> QBlock::getPluginInfo() const
{
    return m_pluginInfoList;
}


void QBlock::makeBackwardCompatibility() {

    // it supports obsoletted m_hashAttributes t1, t2, ..., t8
    // and converts to attribute vars with comma delemited values
    // versions before 0.9.7
    if(isBockType(QFlowEnum::BlockType::IO)
            || isBockType(QFlowEnum::BlockType::OU))
    {
        QStringList sl;
        for(int i = 1; i <= 8; ++i)
        {
            QString attr = QString("t%1").arg(i);
            if(!m_hashAttributes.value(attr).isEmpty())
            {
                sl << m_hashAttributes.value(attr, "");
            }
            m_hashAttributes.remove(attr);
        }

        if(!sl.empty())
        {
            QString vars = sl.join(",");
            m_hashAttributes.insert("vars", vars);
        }
    }

    if(isBockType(QFlowEnum::BlockType::Algorithm))
    {
        m_hashAttributes.insert("version", CVV_VERSION);
        m_hashAttributes.insert("describe", m_descibe);
        m_hashAttributes.insert("scene", m_scene);
    }

    for(int i = 0; i < m_lstChildItems.size(); ++i)
    {
        m_lstChildItems.at(i)->makeBackwardCompatibility();
    }
}

void QBlock::setAlgorithmParams(const QList<Interface::FlowCellParam> &lstAlgParam)
{
    m_lstAlgParam = lstAlgParam;
}

QList<Interface::FlowCellParam> QBlock::getAlgorithmParams() const
{
    return m_lstAlgParam;
}

void QBlock::setId(const QString &id)
{
    m_strId = id;
}

QString QBlock::id() const
{
    return m_strId;
}

void QBlock::setPreId(const QString &id)
{
    m_strPreId = id;
    m_hashAttributes["preId"] = id;
}

QString QBlock::preId() const
{
    return m_strPreId;
}

void QBlock::createCellParamNode(QDomDocument &doc, QDomElement &cellElement) const
{
    for(int i = 0;i < m_pluginInfoList.size();i++)
    {
        CVV::Interface::FlowCellParam param = m_pluginInfoList.at(i);

        if(!param.isSave().contains("true")){
            continue;
        }

        QString strType = param.type();
        QString tagName = param.code();
        QDomElement child = doc.createElement(tagName);
        child.setAttribute("Name", param.property("Name").toString());
        child.setAttribute("Value", param.property("Value").toString());
        child.setAttribute("AssociatedCode", param.property("AssociatedCode").toString());
        QVariant var = param.property("UserTypeValue");
        QString userTypeCode = parserParamString(strType);
        createUserTypeValueNode(doc, child, var, userTypeCode);
        cellElement.appendChild(child);
    }
}

void QBlock::createAlgorithmParamNode(QDomDocument &doc, QDomElement &algEle) const
{
    for(int i = 0; i < m_lstAlgParam.size(); i++)
    {
        CVV::Interface::FlowCellParam param = m_lstAlgParam.at(i);
        QString strType = param.type();
        QString tagName = param.code();
        QDomElement child = doc.createElement(tagName);
        child.setAttribute("Name", param.property("Name").toString());
        child.setAttribute("Value", param.property("Value").toString());
        QVariant var = param.property("UserTypeValue");
        QString userTypeCode = parserParamString(strType);
        createUserTypeValueNode(doc, child, var, userTypeCode);
        algEle.appendChild(child);
    }
}

void QBlock::createUserTypeValueNode(QDomDocument &doc, QDomElement &ele, const QVariant &userTypeValue, const QString &userTypeCode) const
{
    if (!userTypeValue.isValid() || userTypeCode.isEmpty())
    {
        return;
    }
    if (userTypeValue.canConvert<QList<QPointF>>())
    {
        QList<QPointF> lstPoint = userTypeValue.value<QList<QPointF>>();
        if (lstPoint.isEmpty())
        {
            return;
        }
        for (auto point : qAsConst(lstPoint))
        {
            QDomElement pointEle = doc.createElement("QPointF");
            pointEle.setAttribute("x", QString::number(point.x()));
            pointEle.setAttribute("y", QString::number(point.y()));
            ele.appendChild(pointEle);
        }
    }
    else if (userTypeValue.canConvert<QList<std::shared_ptr<CVV::Entity::AbstractEntity>>>())
    {
        QList<std::shared_ptr<CVV::Entity::AbstractEntity>> lstData = userTypeValue.value<QList<std::shared_ptr<CVV::Entity::AbstractEntity>>>();
        for (auto &data : qAsConst(lstData))
        {
            if (!data)
            {
                continue;
            }
            const QMetaObject* metaObject = data->metaObject();
            if (!metaObject)
            {
                continue;
            }

            QDomElement dataEle = doc.createElement(userTypeCode);
            for(int i = metaObject->propertyOffset(); i < metaObject->propertyCount(); ++i)
            {
                QMetaProperty oneProperty = metaObject->property(i);
                QString strPropertyName = oneProperty.name();
                dataEle.setAttribute(strPropertyName, oneProperty.read(data.get()).toString());
            }
            ele.appendChild(dataEle);
        }
    }
    else if (userTypeValue.canConvert<QList<QList<double>>>())
    {
        QList<QList<double>> lstWarpMat = userTypeValue.value<QList<QList<double>>>();
        for (auto row : qAsConst(lstWarpMat))
        {
            QDomElement matEle = doc.createElement("Mat");
            QStringList lstValue;
            for (auto col : qAsConst(row))
            {
                lstValue << QString::number(col);
            }
            matEle.setAttribute("row", lstValue.join(","));
            ele.appendChild(matEle);
        }
    }
    else if (userTypeValue.canConvert<QPoint>())
    {
        QPoint point = userTypeValue.toPoint();
        QDomElement pointEle = doc.createElement("QPoint");
        pointEle.setAttribute("x", QString::number(point.x()));
        pointEle.setAttribute("y", QString::number(point.y()));
        ele.appendChild(pointEle);
    }
    else if (userTypeValue.canConvert<QList<QStringList>>())
    {
        QList<QStringList> lstData = userTypeValue.value<QList<QStringList>>();
        for (auto &data : qAsConst(lstData))
        {
            QDomElement tmpEle = doc.createElement("QStringList");
            tmpEle.setAttribute("Value", data.join(","));
            ele.appendChild(tmpEle);
        }
    }
}

void QBlock::updateAfterInsertNodePreId(const QString &preId, int index)
{
    if (index >= m_lstChildItems.size()
            || index < 0)
    {
        return;
    }

    QBlock *pItem = nullptr;
    while (index < m_lstChildItems.size()) {
        pItem = item(index);
        if (pItem && !pItem->m_bIsBranch)
        {
            break;
        }
        index++;
    }

    if (!pItem)
    {
        return;
    }

    pItem->setPreId(preId);

//    if (!pItem->m_lstChildItems.isEmpty())      // 分支
//    {
//        for (int i = 0; i < pItem->m_lstChildItems.size(); ++i)
//        {
//            QBlock *pBranchItem = pItem->m_lstChildItems.at(i);
//            if (pBranchItem && !pBranchItem->m_lstChildItems.isEmpty())
//            {
//                QBlock *pChildItem = pBranchItem->m_lstChildItems.first();
//                if (pChildItem)
//                {
//                    pChildItem->setPreId(preId);
//                }
//            }
//        }
//    }
}

QString QBlock::parserParamString(const QString &type) const
{
    if (type.isEmpty())
    {
        return "";
    }

    if (!type.contains("<") || !type.contains(">"))
    {
        return type;
    }

    int idx1 = type.indexOf("<");
    idx1 += 1;
    int idx2 = type.indexOf(">");
    QString strRet = type.mid(idx1, idx2 - idx1);

    return strRet.trimmed();
}

QString QBlock::findPreId(QBlock *aBlock)
{
    if (!aBlock)
    {
        return "";
    }

    QStringList lstPreId;
    findChildId(aBlock, lstPreId);

    return lstPreId.join(",");
}

void QBlock::findChildId(QBlock *aBlock, QStringList &lstPreId)
{
    if (!aBlock)
    {
        return;
    }
    if (aBlock->m_lstChildItems.isEmpty())
    {
        lstPreId.push_back(aBlock->id());
        return;
    }

    if (aBlock->m_bIsBranch && !aBlock->m_bBranchEnable)    // 分支不启用情况
    {
        return;
    }

    for (auto item : qAsConst(aBlock->m_lstChildItems))
    {
        if (item && !item->m_lstChildItems.isEmpty() && item->m_bBranchEnable)
        {
            QBlock* pItem = item->m_lstChildItems.last();
            if (pItem)
            {
                if (!pItem->m_lstChildItems.isEmpty())
                {
                    findChildId(pItem, lstPreId);
                }
                else
                {
                    lstPreId.push_back(pItem->id());
                }
            }
        }
    }
}

void QBlock::updateAllNodePreId()
{
    if (!m_pFlowChart)
    {
        return;
    }

    QBlock* pRoot = m_pFlowChart->root();
    if (!pRoot || pRoot->m_lstChildItems.isEmpty())
    {
        return;
    }

    QBlock* pRootBranch = pRoot->m_lstChildItems.first();

    for (int i = 0; i < pRootBranch->m_lstChildItems.size(); ++i)
    {
        if (i == 0)
        {
            QBlock* pFirstItem = pRootBranch->m_lstChildItems.at(i);
            if (pFirstItem)
            {
                if (!pFirstItem->m_bIsBranch)
                {
                    pFirstItem->setPreId("");
                }
                updateAllNodePreId(pFirstItem);
            }
            continue;
        }

        QBlock* pPreItem = pRootBranch->m_lstChildItems.at(i - 1);
        QBlock* pItem = pRootBranch->m_lstChildItems.at(i);
        if (pItem && pPreItem)
        {
            QString strPreId = findPreId(pPreItem);
            if (strPreId.isEmpty())
            {
                continue;
            }

            pItem->setPreId(strPreId);
        }
        updateAllNodePreId(pItem);
    }
}

void QBlock::setBranchEnable(bool bEnable)
{
    if (this->m_bIsBranch)
    {
        m_bBranchEnable = bEnable;
        m_hashAttributes["isEnable"] = (bEnable ? "true" : "false");
    }
}

bool QBlock::branchEnable() const
{
    return m_bBranchEnable;
}


bool QBlock::getKeywordMatchedResult( const QString &keyWord, int seachType)
{
    if(4 == seachType) // ID
    {
        return (keyWord == m_strId);
    }
    //插件信息匹配
    for(int i = 0; i < m_pluginInfoList.size(); i++)
    {
        CVV::Interface::FlowCellParam param = m_pluginInfoList.at(i);

        bool checkRet = checkParamByKeyWord(param, keyWord, seachType);
        if(checkRet)
        {
            return true;
        }
    }

    //算法插件信息匹配
    for(int i= 0; i < m_lstAlgParam.size(); i++)
    {
        CVV::Interface::FlowCellParam param = m_lstAlgParam.at(i);

        bool checkRet = checkParamByKeyWord(param, keyWord, seachType);
        if(checkRet)
        {
            return true;
        }
    }
    return false;
}

void QBlock::setBlockExpandState(bool expandState)
{
    m_bIsExpand = expandState;
    if(!m_bIsExpand)
    {
        m_dWidth = 160;
        m_dHeight = 86;
    }
    else{
        m_dWidth = m_dExpandW ;
        m_dHeight = m_dExpandH;
    }
    m_hashAttributes["blockExpand"] = (expandState ? "true" : "false");
}

bool QBlock::getBlockExpandState()
{
    return m_bIsExpand;
}

void QBlock::setBlockVisible(bool visible)
{
    m_bVisible = visible;
    m_hashAttributes["blockVisible"] = (visible ? "true" : "false");
}

bool QBlock::getBlockVisible()
{
    return m_bVisible;
}

void QBlock::setDescibe(const QString &desStr)
{
    m_descibe = desStr;
}

QString QBlock::getDescibe() const
{
    return m_descibe;
}

void QBlock::setSceneStr(const QString &scene)
{
    m_scene = scene;
}

QString QBlock::getSceneStr() const
{
    return m_scene;
}

void QBlock::updateAllNodePreId(QBlock *aBlock)
{
    if (!aBlock)
    {
        return;
    }

    for (int i = 0; i < aBlock->m_lstChildItems.size(); ++i)
    {
        if (i == 0)
        {
            QBlock* pFirstItem = aBlock->m_lstChildItems.at(i);
            if (pFirstItem)
            {
                QBlock* pParentBlock = aBlock->m_pParentBlock;
                if (pParentBlock && !pFirstItem->m_bIsBranch)
                {
                    if ("false" == pParentBlock->m_hashAttributes.value("isPlugin"))
                    {
                        pFirstItem->setPreId(pParentBlock->preId());
                    }
                    else
                    {
                        pFirstItem->setPreId(pParentBlock->id());
                    }
                }
                updateAllNodePreId(pFirstItem);
            }
            continue;
        }

        QBlock* pPreItem = aBlock->m_lstChildItems.at(i - 1);
        QBlock* pItem = aBlock->m_lstChildItems.at(i);
        if (pItem && pPreItem)
        {
            if (pPreItem->m_bIsBranch && pItem->m_bIsBranch)
            {
                updateAllNodePreId(pPreItem);
                updateAllNodePreId(pItem);
                continue;
            }

            QString strPreId = findPreId(pPreItem);
            if (strPreId.isEmpty())
            {
                continue;
            }

            pItem->setPreId(strPreId);

            updateAllNodePreId(pItem);
        }
    }
}

bool QBlock::checkParamByKeyWord(Interface::FlowCellParam &param, const QString &keyWord, int serchType)
{
    if(0 == serchType) // 普通模式
    {
        return commonMatch(param, keyWord, false);
    }
    else if( 1 == serchType) // 全词匹配
    {
        return wholdWordMatch(param, keyWord, false);
    }
    else if( 2 == serchType) // 大小写区分
    {
        return commonMatch(param, keyWord, true);
    }
    else if( 3 == serchType) // 全词匹配且区分大小写
    {
        return wholdWordMatch(param, keyWord, true);
    }
    else if(5 == serchType)
    {
        return RegExpMatch(param, keyWord);
    }
    return false;
}

bool QBlock::commonMatch(FlowCellParam &param, const QString &keyWord, bool bFlag)
{
    QString curplugId = param.pluginId();
    if(bFlag && (!curplugId.isEmpty()) &&
       curplugId.contains(keyWord))
    {
        return true;
    }
    else if((!bFlag) && (!curplugId.isEmpty()) &&
            curplugId.contains(keyWord, Qt::CaseInsensitive))
    {
        return true;
    }

    QString pluginCode = param.pluginCode();
    if(bFlag && (!pluginCode.isEmpty()) &&
            pluginCode.contains(keyWord))
    {
        return true;
    }
    else if((!bFlag) && (!pluginCode.isEmpty()) &&
            pluginCode.contains(keyWord, Qt::CaseInsensitive))
    {
        return true;
    }

    QString curValue = param.value();
    if(bFlag && (!curValue.isEmpty()) && curValue.contains(keyWord))
    {
        return true;
    }
    else if((!bFlag) && (!curValue.isEmpty()) && curValue.contains(keyWord, Qt::CaseInsensitive))
    {
        return true;
    }

    QVariant userValue = param.userTypeValue();
    if(userValue.isValid())
    {
        if (userValue.canConvert<QString>())
        {
           QString curStr = userValue.value<QString>();
           if(bFlag && (!curStr.isEmpty()) && curStr.contains(keyWord))
           {
               return true;
           }
           else if((!bFlag) && (!curStr.isEmpty()) && curStr.contains(keyWord, Qt::CaseInsensitive))
           {
               return true;
           }
        }
        else if (userValue.canConvert<QList<std::shared_ptr<CVV::Entity::AbstractEntity>>>())
        {
            QList<std::shared_ptr<CVV::Entity::AbstractEntity>> lstData = userValue.value<QList<std::shared_ptr<CVV::Entity::AbstractEntity>>>();
            for (auto &data : qAsConst(lstData))
            {
                if (!data)
                {
                    continue;
                }
                const QMetaObject* metaObject = data->metaObject();
                if (!metaObject)
                {
                    continue;
                }

                for(int i = metaObject->propertyOffset(); i < metaObject->propertyCount(); ++i)
                {
                    QMetaProperty oneProperty = metaObject->property(i);
                    QString strPropertyName = oneProperty.name();
                    QVariant varData = data->property(strPropertyName.toLocal8Bit().constData());
                    if(varData.isValid())
                    {
                        QString keyStr = keyWord;
                        return VariantMatch(0, bFlag, keyStr, varData);
                    }
                }
            }
        }
        else if(userValue.canConvert<QList<QStringList>>())
        {
            QList<QStringList> lstData = userValue.value<QList<QStringList>>();
            for (auto &data : qAsConst(lstData))
            {
                for(auto &str: qAsConst(data))
                {
                    if(bFlag && (!str.isEmpty()) && str.contains(keyWord))
                    {
                        return true;
                    }
                    else if((!bFlag) && (!str.isEmpty()) && str.contains(keyWord, Qt::CaseInsensitive))
                    {
                        return true;
                    }
                }
            }
        }
    }
    return false;
}

bool QBlock::wholdWordMatch(FlowCellParam &param, const QString &keyWord, bool bFlag)
{
    QString curplugId = param.pluginId();
    if(bFlag && (!curplugId.isEmpty()) &&
            (0 == curplugId.compare(keyWord)))
    {
        return true;
    }
    else if((!bFlag) && (!curplugId.isEmpty()) &&
            (0 == curplugId.compare(keyWord, Qt::CaseInsensitive)))
    {
        return true;
    }

    QString pluginCode = param.pluginCode();
    if(bFlag && (!pluginCode.isEmpty()) &&
            (0 == pluginCode.compare(keyWord)))
    {
        return true;
    }
    else if((!bFlag) && (!pluginCode.isEmpty()) &&
            (0 == pluginCode.compare(keyWord, Qt::CaseInsensitive)))
    {
        return true;
    }

    QString curValue = param.value();
    if(bFlag && (!curValue.isEmpty()) &&
            (0 == curValue.compare(keyWord)))
    {
        return true;
    }
    else if((!bFlag) && (!curValue.isEmpty()) &&
            (0 == curValue.compare(keyWord, Qt::CaseInsensitive)))
    {
        return true;
    }

    QVariant userValue = param.userTypeValue();
    if(userValue.isValid())
    {
        if (userValue.canConvert<QString>())
        {
           QString curStr = userValue.value<QString>();
           if(bFlag && (!curStr.isEmpty()) &&
                   (0 == curStr.compare(keyWord)))
           {
               return true;
           }
           else if((!bFlag) && (!curStr.isEmpty()) &&
                   (0 == curStr.compare(keyWord, Qt::CaseInsensitive)))
           {
               return true;
           }
        }
        else if (userValue.canConvert<QList<std::shared_ptr<CVV::Entity::AbstractEntity>>>())
        {
            QList<std::shared_ptr<CVV::Entity::AbstractEntity>> lstData = userValue.value<QList<std::shared_ptr<CVV::Entity::AbstractEntity>>>();
            for (auto &data : qAsConst(lstData))
            {
                if (!data)
                {
                    continue;
                }
                const QMetaObject* metaObject = data->metaObject();
                if (!metaObject)
                {
                    continue;
                }

                for(int i = metaObject->propertyOffset(); i < metaObject->propertyCount(); ++i)
                {
                    QMetaProperty oneProperty = metaObject->property(i);
                    QString strPropertyName = oneProperty.name();
                    QVariant varData = data->property(strPropertyName.toLocal8Bit().constData());
                    if(varData.isValid())
                    {
                        QString keyStr = keyWord;
                        return VariantMatch(1, bFlag, keyStr, varData);
                    }
                }
            }
        }
        else if(userValue.canConvert<QList<QStringList>>())
        {
            QList<QStringList> lstData = userValue.value<QList<QStringList>>();
            for (auto &data : qAsConst(lstData))
            {
                for(auto &str: qAsConst(data))
                {
                    if(bFlag && (!str.isEmpty()) &&
                            (0 == str.compare(keyWord)))
                    {
                        return true;
                    }
                    else if((!bFlag) && (!str.isEmpty()) &&
                            (0 == str.compare(keyWord, Qt::CaseInsensitive)))
                    {
                        return true;
                    }
                }
            }
        }
    }
    return false;
}

bool QBlock::RegExpMatch(FlowCellParam &param, const QString &keyWord)
{
    QRegExp regex(keyWord);
    QString curplugId = param.pluginId();
    if((!curplugId.isEmpty()) && regex.exactMatch(curplugId))
    {
        return true;
    }

    QString pluginCode = param.pluginCode();
    if((!pluginCode.isEmpty()) &&regex.exactMatch(pluginCode))
    {
        return true;
    }

    QString curValue = param.value();
    if((!curValue.isEmpty()) &&regex.exactMatch(curValue))
    {
        return true;
    }

    QVariant userValue = param.userTypeValue();
    if(userValue.isValid())
    {
        if (userValue.canConvert<QString>())
        {
           QString curStr = userValue.value<QString>();
           if((!curStr.isEmpty()) &&regex.exactMatch(curStr))
           {
               return true;
           }
        }
        else if (userValue.canConvert<QList<std::shared_ptr<CVV::Entity::AbstractEntity>>>())
        {
            QList<std::shared_ptr<CVV::Entity::AbstractEntity>> lstData = userValue.value<QList<std::shared_ptr<CVV::Entity::AbstractEntity>>>();
            for (auto &data : qAsConst(lstData))
            {
                if (!data)
                {
                    continue;
                }
                const QMetaObject* metaObject = data->metaObject();
                if (!metaObject)
                {
                    continue;
                }

                for(int i = metaObject->propertyOffset(); i < metaObject->propertyCount(); ++i)
                {
                    QMetaProperty oneProperty = metaObject->property(i);
                    QString strPropertyName = oneProperty.name();
                    QVariant varData = data->property(strPropertyName.toLocal8Bit().constData());
                    if(varData.isValid())
                    {
                        QString keyStr = keyWord;
                        return VariantMatch(2, true, keyStr, varData);
                    }
                }
            }
        }
        else if(userValue.canConvert<QList<QStringList>>())
        {
            QList<QStringList> lstData = userValue.value<QList<QStringList>>();
            for (auto &data : qAsConst(lstData))
            {
                for(auto &str: qAsConst(data))
                {
                    if((!str.isEmpty()) && regex.exactMatch(str))
                    {
                        return true;
                    }
                }
            }
        }
    }
    return false;
}

bool QBlock::VariantMatch(int matchId, bool bFlag, QString &srcStr, QVariant &var)
{
    QString valStr = "";
    QVariant::Type type = var.type();
    if(type > QVariant::Bool && type < QVariant::Double)
    {
        int iV = var.toInt();
        valStr = QString::number(iV);
    }
    else if(QVariant::Double == type)
    {
        double d = var.toDouble();
        valStr = QString::number(d);
    }
    else if(QVariant::Char == type)
    {
        QChar ch = var.toChar();
        valStr = QString(ch);
    }
    else if(QVariant::String == type)
    {
        valStr = var.toString();
    }
    else if(QVariant::StringList == type)
    {
        QStringList strLst = var.toStringList();
        for(auto &str:strLst)
        {
            valStr.append(str.trimmed());
        }
    }
    else if(QVariant::ByteArray == type)
    {
        valStr = QString(var.toByteArray());
    }

    if(!valStr.isEmpty())
    {
        switch (matchId) {
        case 0:
        {
            if(bFlag && valStr.contains(srcStr))
            {
                return true;
            }
            else if((!bFlag) && valStr.contains(srcStr, Qt::CaseInsensitive))
            {
                return true;
            }
        }
            break;
        case 1:
        {
            if(bFlag && (0 == valStr.compare(srcStr)))
            {
                return true;
            }
            else if((!bFlag) && (0 == valStr.compare(srcStr, Qt::CaseInsensitive)))
            {
                return true;
            }
        }
            break;
        case 2:
        {
            QRegExp regex(srcStr);
            if(regex.exactMatch(valStr))
            {
                return true;
            }
        }
            break;
        default:
            break;
        }
    }
    return false;
}


}
}
